package com.fx.zmlzml.exception;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fx.zmlzml.common.response.Result;
import com.fx.zmlzml.util.MessageUtils;
import jakarta.validation.ConstraintViolationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.resource.NoResourceFoundException;

import java.io.IOException;
import java.sql.SQLException;
import java.util.NoSuchElementException;
import java.util.stream.Collectors;

/**
 * 全局异常处理类
 */
@RestControllerAdvice
public class GlobalExceptionHandler {
    
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    // ==================== Spring Security 相关异常 ====================

    @ExceptionHandler(BadCredentialsException.class)
    public Result<?> handleBadCredentialsException(BadCredentialsException e) {
        logger.error("登录失败：", e);
        return Result.error(401, MessageUtils.getMessage("exception.bad_credentials"));
    }

    @ExceptionHandler(AccessDeniedException.class)
    public Result<?> handleAccessDeniedException(AccessDeniedException e) {
        logger.error("访问被拒绝：", e);
        return Result.error(403, MessageUtils.getMessage("exception.access_denied"));
    }

    @ExceptionHandler(AuthenticationException.class)
    public Result<?> handleAuthenticationException(AuthenticationException e) {
        logger.error("身份验证异常：", e);
        return Result.error(401, MessageUtils.getMessage("exception.authentication_required"));
    }

    // ==================== Java 标准异常 ====================

    /**
     * 处理空指针异常
     */
    @ExceptionHandler(NullPointerException.class)
    public Result<?> handleNullPointerException(NullPointerException e) {
        logger.error("空指针异常：", e);
        return Result.error(500, MessageUtils.getMessage("exception.null_pointer"));
    }
    
    /**
     * 处理算术异常
     */
    @ExceptionHandler(ArithmeticException.class)
    public Result<?> handleArithmeticException(ArithmeticException e) {
        logger.error("算术异常：", e);
        return Result.i18nError(ErrorEnum.ARITHMETIC_ERROR.getCode(),
                        "exception.arithmetic", null);
    }

    /**
     * 处理类型转换异常
     */
    @ExceptionHandler(ClassCastException.class)
    public Result<?> handleClassCastException(ClassCastException e) {
        logger.error("类型转换异常：", e);
        return Result.i18nError(ErrorEnum.CLASS_CAST_ERROR.getCode(),
                        "exception.class_cast", null);
    }

    /**
     * 处理非法状态异常
     */
    @ExceptionHandler(IllegalStateException.class)
    public Result<?> handleIllegalStateException(IllegalStateException e) {
        logger.error("非法状态异常：", e);
        return Result.i18nError(ErrorEnum.ILLEGAL_STATE.getCode(),
                        "exception.illegal_state", null);
    }

    /**
     * 处理非法参数异常 - 整合了所有IllegalArgumentException子类异常的处理
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public Result<?> handleIllegalArgumentException(IllegalArgumentException e) {
        // 优先处理特定类型的IllegalArgumentException
        if (e.getMessage() != null) {
            if (e.getMessage().contains("Content-Length")) {
                logger.warn("需要Content-Length异常：", e);
                return Result.i18nError(ErrorEnum.LENGTH_REQUIRED.getCode(),
                                "exception.length_required", null);
            } else if (e.getMessage().contains("URI too long")) {
                logger.warn("请求URI过长异常：", e);
                return Result.i18nError(ErrorEnum.URI_TOO_LONG.getCode(),
                                "exception.uri_too_long", null);
            } else if (e.getMessage().contains("Range")) {
                logger.warn("请求范围不满足异常：", e);
                return Result.i18nError(ErrorEnum.REQUESTED_RANGE_NOT_SATISFIABLE.getCode(),
                                "exception.requested_range_not_satisfiable", null);
            } else if (e.getMessage().contains("HTTP version")) {
                logger.warn("不支持的HTTP版本异常：", e);
                return Result.i18nError(ErrorEnum.HTTP_VERSION_NOT_SUPPORTED.getCode(),
                                "exception.http_version_not_supported", null);
            }
        }
        
        // 默认处理其他所有IllegalArgumentException
        logger.error("非法参数异常：", e);
        return Result.i18nError(ErrorEnum.ILLEGAL_ARGUMENT.getCode(),
                        "exception.illegal_argument", null);
    }

    /**
     * 处理资源不存在异常
     */
    @ExceptionHandler(NoSuchElementException.class)
    public Result<?> handleNoSuchElementException(NoSuchElementException e) {
        logger.warn("资源不存在异常：", e);
        return Result.i18nError(ErrorEnum.RESOURCE_NOT_FOUND.getCode(), 
                        "exception.resource_not_found", null);
    }

    // ==================== JSON处理异常 ====================

    /**
     * 处理JSON处理异常
     */
    @ExceptionHandler(JsonProcessingException.class)
    public Result<?> handleJsonProcessingException(JsonProcessingException e) {
        logger.error("JSON处理异常：", e);
        return Result.error(500, MessageUtils.getMessage("exception.json_processing"));
    }

    // ==================== 数据库相关异常 ====================

    /**
     * 处理数据库异常
     */
    @ExceptionHandler(SQLException.class)
    public Result<?> handleSQLException(SQLException e) {
        logger.error("数据库异常：错误码={}, 状态码={}", e.getErrorCode(), e.getSQLState(), e);
        return Result.error(500, MessageUtils.getMessage("exception.sql"));
    }

    /**
     * 处理数据完整性违反异常（如唯一约束违反）
     */
    @ExceptionHandler(DataIntegrityViolationException.class)
    public Result<?> handleDataIntegrityViolationException(DataIntegrityViolationException e) {
        logger.error("数据完整性违反异常：", e);
        return Result.i18nError(ErrorEnum.DATA_INTEGRITY_VIOLATION.getCode(),
                        "exception.data_integrity_violation", null);
    }

    /**
     * 处理请求冲突异常
     */
    @ExceptionHandler({java.sql.SQLIntegrityConstraintViolationException.class})
    public Result<?> handleConflictException(Exception e) {
        logger.error("请求冲突异常：", e);
        return Result.i18nError(ErrorEnum.CONFLICT.getCode(),
                        "exception.conflict", null);
    }

    // ==================== Spring Web 相关异常 ====================

    /**
     * 处理HTTP请求方法不支持异常
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public Result<?> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
        logger.warn("HTTP请求方法不支持异常：请求方法={}, 支持的方法={}", e.getMethod(), String.join(", ", e.getSupportedMethods()));
        return Result.i18nError(ErrorEnum.BUSINESS_ERROR.getCode(),
                        "exception.method_not_allowed", new Object[]{e.getMethod(), String.join(", ", e.getSupportedMethods())});
    }

    /**
     * 处理HTTP媒体类型不支持异常
     */
    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public Result<?> handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) {
        logger.warn("HTTP媒体类型不支持异常：请求媒体类型={}, 支持的媒体类型={}", e.getContentType(), e.getSupportedMediaTypes());
        return Result.i18nError(ErrorEnum.BUSINESS_ERROR.getCode(),
                        "exception.unsupported_media_type", new Object[]{e.getContentType(), e.getSupportedMediaTypes()});
    }

    /**
     * 处理HTTP消息不可读异常（如JSON解析错误）
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public Result<?> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
        logger.warn("HTTP消息不可读异常：", e);
        return Result.i18nError(ErrorEnum.PARAM_INVALID.getCode(),
                        "exception.message_not_readable", null);
    }

    /**
     * 处理HTTP内容类型不支持异常
     */
    @ExceptionHandler(HttpMediaTypeNotAcceptableException.class)
    public Result<?> handleHttpMediaTypeNotAcceptableException(HttpMediaTypeNotAcceptableException e) {
        logger.warn("HTTP内容类型不支持异常：支持的媒体类型={}", e.getSupportedMediaTypes());
        return Result.i18nError(ErrorEnum.NOT_ACCEPTABLE.getCode(),
                        "exception.not_acceptable", new Object[]{e.getSupportedMediaTypes()});
    }

    /**
     * 处理没有找到处理器异常（404错误）
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    public Result<?> handleNoHandlerFoundException(NoHandlerFoundException e) {
        logger.warn("未找到请求的处理器：URL={}, 方法={}", e.getRequestURL(), e.getHttpMethod());
        return Result.i18nError(ErrorEnum.RESOURCE_NOT_FOUND.getCode(),
                        "exception.no_handler_found", new Object[]{e.getRequestURL()});
    }

    /**
     * 处理资源不存在异常 - 当请求的资源不存在时触发
     */
    @ExceptionHandler(NoResourceFoundException.class)
    public Result<?> handleNoResourceFoundException(NoResourceFoundException e) {
        logger.warn("资源不存在异常：", e);
        return Result.i18nError(ErrorEnum.RESOURCE_NOT_FOUND.getCode(),
                        "exception.resource_not_found", null);
    }

    /**
     * 处理响应状态异常
     */
    @ExceptionHandler(ResponseStatusException.class)
    public Result<?> handleResponseStatusException(ResponseStatusException e) {
        logger.warn("响应状态异常：状态码={}, 消息={}", e.getStatusCode(), e.getMessage());
        if (e.getStatusCode() == HttpStatus.GONE) {
            return Result.i18nError(ErrorEnum.GONE.getCode(),
                            "exception.gone", null);
        }
        // 其他状态码的处理会在通用异常处理中进行
        return handleException(e);
    }

    // ==================== 参数校验相关异常 ====================

    /**
     * 处理请求参数校验异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        String errorMsg = e.getBindingResult().getFieldErrors().stream()
                .map(fieldError -> fieldError.getField() + ":" + fieldError.getDefaultMessage())
                .collect(Collectors.joining(", "));
        logger.warn("参数校验异常：{}", errorMsg);
        return Result.i18nError(ErrorEnum.PARAM_VALIDATION_ERROR.getCode(), 
                        "exception.param_validation", new Object[]{errorMsg});
    }

    /**
     * 处理参数类型不匹配异常
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public Result<?> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) {
        logger.warn("参数类型不匹配异常：参数={}, 预期类型={}, 实际值={}", 
                e.getName(), e.getRequiredType() != null ? e.getRequiredType().getName() : "未知", e.getValue());
        return Result.i18nError(ErrorEnum.PARAM_TYPE_ERROR.getCode(), 
                        "exception.param_type", new Object[]{e.getName()});
    }

    /**
     * 处理参数约束违反异常（JSR-380验证）
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public Result<?> handleConstraintViolationException(ConstraintViolationException e) {
        String errorMsg = e.getConstraintViolations().stream()
                .map(violation -> violation.getPropertyPath() + ":" + violation.getMessage())
                .collect(Collectors.joining(", "));
        logger.warn("参数约束违反异常：{}", errorMsg);
        return Result.i18nError(ErrorEnum.PARAM_VALIDATION_ERROR.getCode(),
                        "exception.param_constraint_violation", new Object[]{errorMsg});
    }

    /**
     * 处理缺失请求参数异常
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public Result<?> handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
        logger.warn("缺失请求参数异常：参数名={}, 参数类型={}", e.getParameterName(), e.getParameterType());
        return Result.i18nError(ErrorEnum.PARAM_MISSING.getCode(),
                        "exception.missing_parameter", new Object[]{e.getParameterName()});
    }

    /**
     * 处理绑定异常（@Valid注解验证失败）
     */
    @ExceptionHandler(BindException.class)
    public Result<?> handleBindException(BindException e) {
        String errorMsg = e.getBindingResult().getFieldErrors().stream()
                .map(fieldError -> fieldError.getField() + ":" + fieldError.getDefaultMessage())
                .collect(Collectors.joining(", "));
        logger.warn("绑定异常：{}", errorMsg);
        return Result.i18nError(ErrorEnum.PARAM_VALIDATION_ERROR.getCode(),
                        "exception.param_bind_error", new Object[]{errorMsg});
    }

    // ==================== HTTP状态码相关异常 ====================

    /**
     * 处理超时异常 - 整合了请求超时和网关超时的处理
     */
    @ExceptionHandler({java.net.SocketTimeoutException.class, java.util.concurrent.TimeoutException.class})
    public Result<?> handleTimeoutException(Exception e) {
        // 区分不同类型的超时情况
        if (e.getMessage() != null && e.getMessage().contains("connect timed out")) {
            logger.error("网关超时异常：", e);
            return Result.i18nError(ErrorEnum.GATEWAY_TIMEOUT.getCode(),
                            "exception.gateway_timeout", null);
        } else {
            logger.error("请求超时异常：", e);
            return Result.i18nError(ErrorEnum.REQUEST_TIMEOUT.getCode(),
                            "exception.request_timeout", null);
        }
    }

    /**
     * 处理前置条件失败异常
     */
    @ExceptionHandler({java.util.ConcurrentModificationException.class})
    public Result<?> handlePreconditionFailed(Exception e) {
        logger.warn("前置条件失败异常：", e);
        return Result.i18nError(ErrorEnum.PRECONDITION_FAILED.getCode(),
                        "exception.precondition_failed", null);
    }

    /**
     * 处理请求体过大异常
     */
    @ExceptionHandler({org.springframework.web.multipart.MaxUploadSizeExceededException.class, java.io.IOException.class})
    public Result<?> handlePayloadTooLarge(Exception e) {
        if (e instanceof org.springframework.web.multipart.MaxUploadSizeExceededException || 
            (e instanceof IOException && e.getMessage() != null && e.getMessage().contains("too large"))) {
            logger.warn("请求体过大异常：", e);
            return Result.i18nError(ErrorEnum.PAYLOAD_TOO_LARGE.getCode(),
                            "exception.payload_too_large", null);
        }
        // 其他IOException会被通用异常处理
        return handleException(e);
    }

    /**
     * 处理期望失败异常
     */
    @ExceptionHandler({java.net.ProtocolException.class})
    public Result<?> handleExpectationFailed(Exception e) {
        if (e instanceof java.net.ProtocolException) {
            logger.warn("期望失败异常：", e);
            return Result.i18nError(ErrorEnum.EXPECTATION_FAILED.getCode(),
                            "exception.expectation_failed", null);
        }
        // 其他异常会被通用异常处理
        return handleException(e);
    }

    /**
     * 处理请求过多异常
     */
    @ExceptionHandler({org.springframework.web.server.ServerWebInputException.class})
    public Result<?> handleTooManyRequests(Exception e) {
        if (e instanceof org.springframework.web.server.ServerWebInputException && 
            e.getMessage() != null && e.getMessage().contains("Too Many Requests")) {
            logger.warn("请求过多异常：", e);
            return Result.i18nError(ErrorEnum.TOO_MANY_REQUESTS.getCode(),
                            "exception.too_many_requests", null);
        }
        logger.warn("服务器输入异常：", e);
        return Result.i18nError(ErrorEnum.PARAM_TYPE_ERROR.getCode(),
                        "exception.bad_request", null);
    }

    /**
     * 处理未实现异常
     */
    @ExceptionHandler(UnsupportedOperationException.class)
    public Result<?> handleNotImplemented(UnsupportedOperationException e) {
        logger.warn("未实现异常：", e);
        return Result.i18nError(ErrorEnum.NOT_IMPLEMENTED.getCode(),
                        "exception.not_implemented", null);
    }

    /**
     * 处理错误的网关异常
     */
    @ExceptionHandler({java.net.ConnectException.class, java.net.UnknownHostException.class})
    public Result<?> handleBadGateway(Exception e) {
        logger.error("错误的网关异常：", e);
        return Result.i18nError(ErrorEnum.BAD_GATEWAY.getCode(),
                        "exception.bad_gateway", null);
    }

    /**
     * 处理服务不可用异常
     */
    @ExceptionHandler(java.util.concurrent.RejectedExecutionException.class)
    public Result<?> handleServiceUnavailable(java.util.concurrent.RejectedExecutionException e) {
        logger.error("服务不可用异常：", e);
        return Result.i18nError(ErrorEnum.SERVICE_UNAVAILABLE.getCode(),
                        "exception.service_unavailable", null);
    }

    /**
     * 处理HTTP客户端错误异常
     */
    @ExceptionHandler(HttpClientErrorException.class)
    public Result<?> handleHttpClientErrorException(HttpClientErrorException e) {
        logger.warn("HTTP客户端错误异常：状态码={}, 消息={}", e.getStatusCode(), e.getMessage());
        return Result.i18nError(ErrorEnum.PARAM_INVALID.getCode(),
                        "exception.param_invalid", null);
    }

    // ==================== 自定义业务异常 ====================

    /**
     * 处理自定义业务异常
     */
    @ExceptionHandler(BusinessException.class)
    public Result<?> handleBusinessException(BusinessException e) {
        logger.error("业务异常：[{}] {}", e.getCode(), e.getMessage());
        return Result.error(e.getCode(), e.getMessage());
    }

    // ==================== 通用异常处理 ====================

    /**
     * 处理其他所有异常
     */
    @ExceptionHandler(Exception.class)
    public Result<?> handleException(Exception e) {
        logger.error("未捕获的系统异常：", e);
        // 默认使用系统错误枚举
        ErrorEnum errorEnum = ErrorEnum.SYSTEM_ERROR;
        
        // 根据异常类型映射到更具体的错误枚举
        if (e instanceof SQLException) {
            errorEnum = ErrorEnum.DATABASE_ERROR;
        }
        
        return Result.i18nError(errorEnum.getCode(), 
                        "exception.system", null);
    }
}